package com.todo.event.activity.application.core.engine.qlexp;

import com.ql.util.express.ExpressRunner;
import com.ql.util.express.IExpressContext;
import com.todo.event.activity.application.handler.bizRuleHandle.RuleHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Map;

/**
 * @author azhebuxing
 * @date 2025/1/9 20:47
 * @description 注：当前语法无法直接验证是否正确，可以通过上线前做一轮【人工验证】，验证成功后再正式上线
 */
@Slf4j
@Component
public class QLExpressManager implements InitializingBean, ApplicationContextAware {

    private ExpressRunner runner;

    private ApplicationContext applicationContext;

    public Object execute(String exp, Map<String, Object> context) throws Exception {
        IExpressContext expressContext = new QLExpressContext(context != null ? context : Collections.EMPTY_MAP, applicationContext);
        return runner.execute(exp, expressContext, null, true, false);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        runner = new ExpressRunner(false, false);
        runner.addOperatorWithAlias("大于", ">", null);
        runner.addOperatorWithAlias("小于", "<", null);
        runner.addOperatorWithAlias("等于", "==", null);
        runner.addOperatorWithAlias("大于等于", ">=", null);
        runner.addOperatorWithAlias("小于等于", "<=", null);

        Map<String, RuleHandler> beanMap = applicationContext.getBeansOfType(RuleHandler.class);

        beanMap.values().forEach(bean -> {
            Method[] methods = bean.getClass().getDeclaredMethods();

            for (Method method : methods) {
                QlRule qlRule = method.getAnnotation(QlRule.class);

                if (qlRule == null) {
                    continue;
                }

                try {
                    runner.addFunctionOfClassMethod(qlRule.methodName(), bean.getClass().getName(), method.getName(),
                            method.getParameterTypes(), null);
                } catch (Exception ex) {
                    log.error("runner.addFunctionOfClassMethod", ex);
                }
            }
        });
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
